/*
 * Copyright (c) 2020 - present, Inspur Genersoft Co., Ltd.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

/*
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.inspur.edp.cef.generator.coreGenerator.base.entitygen.enrichedassoudt;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.inspur.edp.caf.generator.baseInfo.AnnotationInfo;
import com.inspur.edp.caf.generator.baseInfo.AnnotationType;
import com.inspur.edp.caf.generator.baseInfo.TypeInfo;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.cef.gencommon.MediateType;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.gencommon.CefPropertyInfo;
import com.inspur.edp.cef.generator.common.MediatePropertyInfo;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.EntityGeneratorContext;
import com.inspur.edp.cef.generator.coreGenerator.base.entitygen.property.BaseTypePropGenerator;
import com.inspur.edp.cef.generator.entityGenerator.base.elements.ElementAssoGenerator;
import com.inspur.edp.cef.generator.overall.Utils;
import com.inspur.edp.das.commonmodel.IGspCommonElement;
import com.inspur.edp.udt.designtime.api.entity.SimpleDataTypeDef;
import java.lang.reflect.Method;
import java.util.ArrayList;
import org.eclipse.jdt.core.dom.Block;
import org.eclipse.jdt.core.dom.CastExpression;
import org.eclipse.jdt.core.dom.ClassInstanceCreation;
import org.eclipse.jdt.core.dom.IfStatement;
import org.eclipse.jdt.core.dom.InfixExpression;
import org.eclipse.jdt.core.dom.InstanceofExpression;
import org.eclipse.jdt.core.dom.MethodInvocation;
import org.eclipse.jdt.core.dom.ReturnStatement;

public class OrgAssoUdtPropGenerator extends BaseTypePropGenerator {

  public OrgAssoUdtPropGenerator(EntityGeneratorContext parentContext, MediatePropertyInfo propertyInfo) {
    super(convert(parentContext, propertyInfo), propertyInfo.getPropertyName());
  }

  public OrgAssoUdtPropGenerator(EntityGeneratorContext parentContext, MediatePropertyInfo propertyInfo, boolean convertToUpper) {
    super(convert(parentContext, propertyInfo), propertyInfo.getPropertyName(), convertToUpper);
  }

  private static MediatePropertyInfo convert(EntityGeneratorContext parentContext, MediatePropertyInfo propInfo){
    SimpleDataTypeDef udtDef = parentContext.getProjContext().getCefGenContext().getMetadataContent(
        propInfo.getElement().getUdtPkgName(), propInfo.getElement().getUdtID());
    IGspCommonField udtField = udtDef.getContainElements().get(0);
    String packageName = udtDef.getEntityAssemblyInfo().getAssemblyName();
    String className = udtField.getLabelID() + ElementAssoGenerator.nameSuffix;
    return new MediatePropertyInfo(udtField.getLabelID()) {{
      setPropertyType(new TypeInfo(className){{setTypePackageName(packageName);}});
      setElement(propInfo.getElement());
    }};
  }

  @Override
  protected Block buildGetMethodBody() {
    MethodInvocation methodInvocation = ast.newMethodInvocation();
    methodInvocation
        .setName(ast.newSimpleName(Utils.getGetterMethodName(getPropertyInfo().getElement().getLabelID())));
    ReturnStatement returnStatement = ast.newReturnStatement();
    returnStatement.setExpression(methodInvocation);
    Block block = ast.newBlock();
    block.statements().add(returnStatement);
    return block;
  }

  @Override
  protected ArrayList<AnnotationInfo> getGetterAttributeList() {
    java.util.ArrayList<AnnotationInfo> list = super.getGetterAttributeList();
    if (list == null) {
      list = new java.util.ArrayList<AnnotationInfo>();
    }

    if (getPropertyInfo().getExtendInfos().containsKey("AssoUdtAtrribute")) {
      AnnotationInfo annotationInfo = new AnnotationInfo();
      annotationInfo.setAnnotationType(AnnotationType.SingleMember);
      annotationInfo.setTypeInfo(new TypeInfo(JsonIgnore.class));
      annotationInfo.setSingleParam(ast.newBooleanLiteral(true));
      list.add(annotationInfo);
    }
    return list;
  }

  @Override
  protected Block buildSetMethodBody() {
    String enrichecPropName = getPropertyInfo().getPropertyName();
    final String valueIdentifireName = "value";
    String transSetterName =
        "set" + getPropertyInfo().getElement().getLabelID();

    TypeInfo assoinfoType = new TypeInfo(getAssociationTypeName(getPropertyInfo().getElement()));
    assoinfoType.setTypePackageName(getPropertyInfo().getElement().getBelongObject().getGeneratedEntityClassInfo().getClassNamespace());
    assoinfoType.setUseFullName(true);

    Block block = ast.newBlock();

    addIfNullStatement(block, transSetterName);
    addIfInstanceOfStatement(valueIdentifireName, assoinfoType, transSetterName, block);
    setNewEnriched(valueIdentifireName, assoinfoType, transSetterName, block);

    return block;
  }

  private void setNewEnriched(String valueIdentifireName, TypeInfo assoinfoType,
      String setterName, Block block) {
    MethodInvocation setInvocation = ast.newMethodInvocation();
    setInvocation.setName(ast.newSimpleName(setterName));
    ClassInstanceCreation classInstanceCreation = ast.newClassInstanceCreation();
    classInstanceCreation.setType(assoinfoType.getType(ast));
    classInstanceCreation.arguments().add(ast.newSimpleName(valueIdentifireName));
    setInvocation.arguments().add(classInstanceCreation);
    block.statements().add(ast.newExpressionStatement(setInvocation));
  }

  private void addIfInstanceOfStatement(String valueIdentifireName, TypeInfo assoinfoType,
      String setterName, Block block) {
		    /*if(value instanceof xxxx){
        setxxx((xxxx)value);
     }
     */
    IfStatement ifStatement = ast.newIfStatement();
    InstanceofExpression instanceofExpression = ast.newInstanceofExpression();
    instanceofExpression.setLeftOperand(ast.newSimpleName(valueIdentifireName));
    instanceofExpression.setRightOperand(assoinfoType.getType(ast));
    ifStatement.setExpression(instanceofExpression);
    Block thenBlock = ast.newBlock();
    MethodInvocation setInvocation = ast.newMethodInvocation();
    setInvocation.setName(ast.newSimpleName(setterName));
    CastExpression castExpression = ast.newCastExpression();
    castExpression.setType(assoinfoType.getType(ast));
    castExpression.setExpression(ast.newSimpleName(valueIdentifireName));
    setInvocation.arguments().add(castExpression);
    thenBlock.statements().add(ast.newExpressionStatement(setInvocation));
    thenBlock.statements().add(ast.newReturnStatement());
    ifStatement.setThenStatement(thenBlock);
    block.statements().add(ifStatement);
  }

  private void addIfNullStatement(Block block, String setterName) {
		    /*if(value == null){
        setxxx(null);
     }
     */
    IfStatement nullIfStatement = ast.newIfStatement();
    InfixExpression infixExpression = ast.newInfixExpression();
    infixExpression.setLeftOperand(ast.newSimpleName("value"));
    infixExpression.setOperator(InfixExpression.Operator.EQUALS);
    infixExpression.setRightOperand(ast.newNullLiteral());
    nullIfStatement.setExpression(infixExpression);
    Block nullIfBlock = ast.newBlock();
    MethodInvocation setInvocation = ast.newMethodInvocation();
    setInvocation.setName(ast.newSimpleName(setterName));
    setInvocation.arguments().add(ast.newNullLiteral());
    nullIfBlock.statements().add(ast.newExpressionStatement(setInvocation));
    nullIfBlock.statements().add(ast.newReturnStatement());
    nullIfStatement.setThenStatement(nullIfBlock);
    block.statements().add(nullIfStatement);
  }

  public static String getAssociationTypeName(IGspCommonField element) {
    return ((IGspCommonElement) element).getAssociationTypeName();
  }
}
